#include "World.h"

int				WORLD_HEIGHT;
int				WORLD_WIDTH;

Maze::Maze()
{
	//Set the world size to a value between 5 and 15 , (x,y)
	// x * y
	WORLD_HEIGHT = 4 + (rand() % 11) + 1;
	WORLD_WIDTH = 4 + (rand() % 11) + 1;

	Create();
}

Maze::~Maze()
{
	Delete();
}

//needs a valid world_height and world_width
void Maze::Create()
{
	COORD XY;
	XY.X = (rand() % WORLD_WIDTH);
	XY.Y = (rand() % WORLD_HEIGHT);
	
	//If the value is the start position set it at the opposite
	if(!(XY.X == 0 && XY.Y == 0))
		m_EndItem = new Pickup(D3DXVECTOR3((float)((XY.X + 1)* 30 - 15),(float)((XY.Y + 1) * 30 - 15), 0.0f),END_MARKER_TYPE,CHARACTER_MESH,GREEN_TEXTURE,1);
	else
	{
		m_EndItem = new Pickup(D3DXVECTOR3((float)(WORLD_WIDTH * 30 - 15),(float)(WORLD_HEIGHT * 30 - 15),.0f),END_MARKER_TYPE,CHARACTER_MESH,GREEN_TEXTURE,1);
	}
	//Create and init both ** array's
	//Items and the grid
	m_ppItemPos = new bool*[WORLD_HEIGHT];
	m_clppMyGrid = new Node*[WORLD_HEIGHT];
	for(int y = 0;y < WORLD_HEIGHT;++y)
	{
		m_ppItemPos[y] = new bool[WORLD_WIDTH];
		m_clppMyGrid[y] = new Node[WORLD_WIDTH];
		for(int x = 0;x < WORLD_WIDTH;++x)
		{
			m_clppMyGrid[y][x].Init(x,y);
			m_ppItemPos[y][x] = false;
		}
	}
	m_ppItemPos[XY.Y][XY.X] = true;
	m_ppItemPos[0][0] = true;
}

void Maze::Delete()
{
	//deletes everything created by new
	for(int y = 0;y < WORLD_HEIGHT;++y)
	{
		delete [] m_clppMyGrid[y];
		delete [] m_ppItemPos[y];
	}
	delete [] m_clppMyGrid;
	delete [] m_ppItemPos;
	delete m_EndItem;
	m_AllEnemies.Clear();
	m_AllItems.Clear();
}

void Maze::Reset()
{
	Delete();
	WORLD_HEIGHT = 5 + (rand() % 10) + 1;
	WORLD_WIDTH = 5 + (rand() % 10) + 1;
	Create();
}

//Is not called in the intializer
// It only is used by the game to get a new map
// Can only be called once until reset map is called again
void Maze::CreateMap(int x,int y)
{
	CheckDirections(x,y);
	static int SPAWN = 0;
	
	while(m_clppMyGrid[y][x].CanGoDirection())
	{
		Enemy* Mob;
		Pickup* GOLD;
		++SPAWN;
		if(SPAWN >= SPAWN_RATE)
		{
			COORD Pos, XY;
			XY.X = (rand() % WORLD_WIDTH);
			XY.Y = (rand() % WORLD_HEIGHT);
			Pos.X = ((XY.X + 1) * 30 - 15);
			Pos.Y = ((XY.Y + 1) * 30 - 15);
			switch(rand() % 2)
			{
			case 0:
				if(!m_ppItemPos[XY.Y][XY.X])
				{
					Mob = new Enemy((float)Pos.X,(float)Pos.Y, 0.0f);
					m_AllEnemies.add(Mob);
					m_ppItemPos[XY.Y][XY.X] = true;
					SPAWN = 0;
				}
				break;
			case 1:
				if(!m_ppItemPos[XY.Y][XY.X])
				{
					GOLD = new Pickup(D3DXVECTOR3((float)Pos.X,(float)Pos.Y, 0.0f),GOLD_TYPE,COIN_MESH,YELLOW_TEXTURE,3);
					m_AllItems.add(GOLD);
					m_ppItemPos[XY.Y][XY.X] = true;
					SPAWN = 0;
				}
				break;
			default:
				break;
			}	
		}
		Mob = NULL;
		GOLD = NULL;

		switch(rand() % 4)
		{
		case NORTH:
			if(m_clppMyGrid[y][x].CanGoDirection(NORTH))
			{
				m_clppMyGrid[y][x].BreakWall(NORTH);
				m_clppMyGrid[y-1][x].BreakWall(SOUTH);
				CreateMap(x,y-1);
			}
			break;
		case SOUTH:
			if(m_clppMyGrid[y][x].CanGoDirection(SOUTH))
			{
				m_clppMyGrid[y][x].BreakWall(SOUTH);
				m_clppMyGrid[y+1][x].BreakWall(NORTH);
				CreateMap(x,y+1);
			}
			break;
		case EAST:
			if(m_clppMyGrid[y][x].CanGoDirection(EAST))
			{
				m_clppMyGrid[y][x].BreakWall(EAST);
				m_clppMyGrid[y][x+1].BreakWall(WEST);
				CreateMap(x+1,y);
			}
			break;
		case WEST:
			if(m_clppMyGrid[y][x].CanGoDirection(WEST))
			{
				m_clppMyGrid[y][x].BreakWall(WEST);
				m_clppMyGrid[y][x-1].BreakWall(EAST);
				CreateMap(x-1,y);
			}
			break;
		}
		CheckDirections(x,y);
	}
}

//Can be called multiple times to push information into lists
// EX. Multiple games can have the same map at the same time
void Maze::SetListInfo(DrawList* drawlist)
{
	drawlist->add(((BaseObject*)(m_EndItem)));

	for(int i = 0;i < m_AllEnemies.getSize();++i)
	{
		drawlist->add(((BaseObject*)(m_AllEnemies.get(i))));
	}
	for(int i = 0;i < m_AllItems.getSize();++i)
	{
		drawlist->add(((BaseObject*)(m_AllItems.get(i))));
	}

	for(int y = 0;y < WORLD_HEIGHT;++y)	{
		for(int x = 0;x < WORLD_WIDTH;++x){
			for(int x2 = 0;x2 < AmountWalls;++x2){
				for(int y2 = 0;y2 < AmountWalls;++y2){
					if(m_clppMyGrid[y][x].CheckBrick(x2,y2))
						drawlist->add(((BaseObject*)(m_clppMyGrid[y][x].GetBrick(x2,y2))));
					if(m_clppMyGrid[y][x].CheckFiller(x2,y2))
						drawlist->add(((BaseObject*)(m_clppMyGrid[y][x].GetFiller(x2,y2))));
				}
			}
		}
	}
}

//Checks the node at specified position, which available directions it has
void Maze::CheckDirections(int x,int y)
{
	//NORTH
	if((y - 1) >= 0 && !m_clppMyGrid[y - 1][x].wasVisited())
	{
		m_clppMyGrid[y][x].SetDirection(NORTH,true);
	}
	else
	{
		m_clppMyGrid[y][x].SetDirection(NORTH,false);
	}
	//SOUTH
	if((y + 1) < WORLD_HEIGHT && !m_clppMyGrid[y + 1][x].wasVisited())
	{
		m_clppMyGrid[y][x].SetDirection(SOUTH,true);
	}
	else
	{
		m_clppMyGrid[y][x].SetDirection(SOUTH,false);
	}
	//EAST
	if((x + 1) < WORLD_WIDTH && !m_clppMyGrid[y][x + 1].wasVisited())
	{
		m_clppMyGrid[y][x].SetDirection(EAST,true);
	}
	else
	{
		m_clppMyGrid[y][x].SetDirection(EAST,false);
	}
	//WEST
	if((x - 1) >= 0 && !m_clppMyGrid[y][x - 1].wasVisited())
	{
		m_clppMyGrid[y][x].SetDirection(WEST,true);
	}
	else
	{
		m_clppMyGrid[y][x].SetDirection(WEST,false);
	}
}